using System;
using System.Collections.Concurrent;
using System.Reflection;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.DependencyInjection;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using SharedKernel.Domain.Events;

namespace SharedKernel.Infrastructure.EventBus.RabbitMQ
{
    /// <summary>
    /// 基于RabbitMQ的事件总线实现
    /// </summary>
    public class RabbitMQEventBus : IEventBus, IDisposable
    {
        private readonly RabbitMQOptions _options;
        private readonly IServiceProvider _serviceProvider;
        private readonly IConnection _connection;
        private readonly IModel _channel;
        private readonly ConcurrentDictionary<Type, List<Type>> _eventHandlers = new();
        private readonly string _exchangeName;
        private readonly bool _persistentMessages;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="options">RabbitMQ配置选项</param>
        /// <param name="serviceProvider">服务提供器</param>
        public RabbitMQEventBus(IOptions<RabbitMQOptions> options, IServiceProvider serviceProvider)
        {
            _options = options.Value;
            _serviceProvider = serviceProvider;
            _exchangeName = _options.ExchangeName;
            _persistentMessages = _options.PersistentMessages;

            // 创建连接和通道
            var factory = new ConnectionFactory
            {
                HostName = _options.HostName,
                Port = _options.Port,
                UserName = _options.UserName,
                Password = _options.Password,
                VirtualHost = _options.VirtualHost,
                AutomaticRecoveryEnabled = true,
                NetworkRecoveryInterval = TimeSpan.FromSeconds(5)
            };

            _connection = factory.CreateConnection();
            _channel = _connection.CreateModel();

            // 声明交换机
            _channel.ExchangeDeclare(
                exchange: _exchangeName,
                type: _options.ExchangeType,
                durable: true,
                autoDelete: false,
                arguments: null);
        }

        /// <summary>
        /// 发布事件
        /// </summary>
        public async Task PublishAsync<TEvent>(TEvent @event) where TEvent : DomainEvent
        {
            var eventType = @event.GetType();
            var eventName = eventType.Name;

            var message = JsonSerializer.Serialize(@event);
            var body = Encoding.UTF8.GetBytes(message);

            var properties = _channel.CreateBasicProperties();
            properties.MessageId = @event.EventId.ToString();
            properties.Timestamp = new AmqpTimestamp(DateTimeOffset.UtcNow.ToUnixTimeSeconds());
            properties.Persistent = _persistentMessages;

            _channel.BasicPublish(
                exchange: _exchangeName,
                routingKey: eventName,
                basicProperties: properties,
                body: body);

            // 异步等待，但不阻塞主线程
            await Task.CompletedTask;
        }

        /// <summary>
        /// 订阅事件
        /// </summary>
        public void Subscribe<TEvent, THandler>() where TEvent : DomainEvent
            where THandler : IEventHandler<TEvent>
        {
            var eventType = typeof(TEvent);
            var handlerType = typeof(THandler);
            var eventName = eventType.Name;

            // 将事件处理器添加到字典
            _eventHandlers.AddOrUpdate(
                eventType,
                _ => new List<Type> { handlerType },
                (_, existingHandlers) =>
                {
                    if (!existingHandlers.Contains(handlerType))
                    {
                        existingHandlers.Add(handlerType);
                    }
                    return existingHandlers;
                });

            // 声明队列并绑定到交换机
            var queueName = $"{eventName}.{handlerType.Name}";
            _channel.QueueDeclare(
                queue: queueName,
                durable: true,
                exclusive: false,
                autoDelete: false,
                arguments: null);

            _channel.QueueBind(
                queue: queueName,
                exchange: _exchangeName,
                routingKey: eventName);

            // 创建消费者
            var consumer = new EventingBasicConsumer(_channel);
            consumer.Received += async (model, ea) =>
            {
                var body = ea.Body.ToArray();
                var message = Encoding.UTF8.GetString(body);

                try
                {
                    var eventInstance = JsonSerializer.Deserialize<TEvent>(message);
                    if (eventInstance != null)
                    {
                        using (var scope = _serviceProvider.CreateScope())
                        {
                            var handler = scope.ServiceProvider.GetService<THandler>();
                            if (handler != null)
                            {
                                await handler.HandleAsync(eventInstance);
                            }
                        }
                    }

                    // 确认消息已处理
                    _channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);
                }
                catch (Exception ex)
                {
                    // 记录异常，并将消息重新入队
                    Console.WriteLine($"处理消息时发生异常: {ex.Message}");
                    _channel.BasicNack(deliveryTag: ea.DeliveryTag, multiple: false, requeue: true);
                }
            };

            _channel.BasicConsume(
                queue: queueName,
                autoAck: false,
                consumer: consumer);
        }

        /// <summary>
        /// 取消订阅事件
        /// </summary>
        public void Unsubscribe<TEvent, THandler>() where TEvent : DomainEvent
            where THandler : IEventHandler<TEvent>
        {
            var eventType = typeof(TEvent);
            var handlerType = typeof(THandler);
            var eventName = eventType.Name;
            var queueName = $"{eventName}.{handlerType.Name}";

            try
            {
                _channel.QueueDelete(queue: queueName);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"删除队列时发生异常: {ex.Message}");
            }
        }

        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            _channel?.Dispose();
            _connection?.Dispose();
        }
    }
}